/**
  ******************************************************************************
  * @file    common.h
  * @author  exatron
  * @version V1.0.0
  * @date    segunda, 22 de dezembro de 2014
  * @brief   Header com definições gerais.
  ******************************************************************************
  * @attention
  *
  *
  ******************************************************************************
  */

/**
  * @addtogroup Common
  * @{
  */

/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef DEFINES_H_
#define DEFINES_H_

/* Includes ------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <sys/resource.h>
#include <semaphore.h>

/* Exported constants --------------------------------------------------------*/

/**
  * @defgroup Common_Exported_Constants
  * @{
  */

/* General */
#define PATH_TEMP "/tmp/exatron/"		/*!< Temp folder */
#define PATH_CONF "/etc/exatron/conf/"	/*!< Conf folder */
#define SYS_DELAY 1000					/*!< Delay para melhorar processamento us */

/* Serial */
#define USART_RX_LEN 1024
#define USART_TX_LEN 4096
#define USART_DEV_CONTROL 	"/dev/ttyS0"
#define USART_DEV_DATA 		"/dev/ttyS1"

/* Sockets */
#define RX_BUF_LEN			4097	/*!< Tamanho do buffer de Rx */
#define TX_BUF_LEN			1024	/*!< Tamanho do buffer de Tx */
#define PIC_BUF_LEN			1000	/*!< Tamanho do buffer do PIC */
#define N_SOCK_TCP			13		/*!< Número máximo de sockets TCP */
#define N_SOCK_UDP			2		/*!< Número máximo de sockets UDP */
#define N_SOCKS				(N_SOCK_TCP + N_SOCK_UDP)
#define N_BACKLOG			11		/*!< Número máximo de conexões */
#define N_SELECT			16		/*!< Linhas de dados p/ select */

/* WF */
#define N_GETWF_BLOCK		1		/*!< Tempo de bloqueio da função de GetIP */

/* Debug */
//#define DEBUG

/**
  * @}
  */

/* Exported types ------------------------------------------------------------*/

/**
  * @defgroup Common_Exported_Types
  * @{
  */

/**
  * @brief	Enumerador de tarefas
  */
typedef enum
{
	WF_GRM 	  = 0,	/*!< WF_GetRadioMAC */
	WF_GIP 	  = 1,	/*!< WF_GetIP */
	WF_GRIP   = 2,	/*!< WF_GetRouterIP */
	WF_CSAP   = 3,	/*!< WF_ConnectSofAP */
	WF_CIK 	  = 4,	/*!< WF_ConnectInfraKey */
	WF_CST 	  = 5,	/*!< WF_ConnectionState */
	WF_DCN 	  = 6,	/*!< WF_Disconnect */
	WF_SCAN   = 7,	/*!< WF_Scan */
	WF_ISD 	  = 8,	/*!< WF_IsScanDone */
	WF_SRT	  = 9,	/*!< WF_ScanResult */
	WF_PIP 	  = 10,	/*!< WF_PingIP */
	WF_IPOK   = 11,	/*!< WF_IsPingOK */
	SCK_IRDR  = 12,	/*!< SCK_IsRxDataReady */
	SCK_IRDR2 = 13, /*!< SCK_IsRxDataReady2 */
	SCK_RXD   = 14,	/*!< SCK_RxData */
	SCK_ITDR  = 15,	/*!< SCK_IsTxDataReady */
	SCK_TXD   = 16,	/*!< SCK_TxData */
	SCK_GSS   = 17,	/*!< SCK_GetStatusSocket */
	SCK_CLOS  = 18,	/*!< SCK_Close */
	TCP_CNC   = 19,	/*!< TCP_ConnClient */
	TCP_OPS   = 20,	/*!< TCP_OpenServer */
	UDP_OPC	  = 21, /*!< UDP_OpenClient */
	UDP_OPS   = 22,	/*!< UDP_OpenServer */
	CFG_SNP	  = 23, /*!< CFG_SetNetworkParameters */
	CFG_GNP	  = 24, /*!< CFG_GetNetworkParameters */
	CFG_STOS  = 25, /*!< CFG_SetTimeOutSocket */
	CFG_GTOS  = 26, /*!< CFG_GetTimeOutSocket */
	CFG_STOU  = 27, /*!< CFG_SetTimeOutUSART */
	CFG_GTOU  = 28, /*!< CFG_GetTimeOutUSART */
	CFG_SBR   = 29, /*!< CFG_SetBaudRate */
	CFG_GBR   = 30, /*!< CFG_GetBaudRate */
	SW_R	  = 31, /*!< SW_Reboot */
	SW_GV     = 32, /*!< SW_GetVersion */
	SW_CB	  = 33, /*!< SW_ClearBusy */
	SW_EXEC	  = 34, /*!< SW_Execute */
	SW_CSC	  = 35, /*!< SW_ConnStatusConf */
	SW_RGC	  = 36, /*!< SW_RingConf */
}TaskID_t;

/**
  * @brief	Enumerador dos ID's dos sockets
  */
typedef enum
{
	TCP_ServerSocketID = 0,	/*!< TCP Server socket */
	UDP_ServerSocketID = 1,	/*!< UDP Server socket */
	TCP_ClientSocketID = 2,	/*!< TCP Client socket */
	UDP_ClientSocketID = 3,	/*!< UDP Client socket */
	Sock0 = 4,				/*!< TCP Client handler */
	Sock1 = 5,				/*!< TCP Client handler */
	Sock2 = 6,				/*!< TCP Client handler */
	Sock3 = 7,				/*!< TCP Client handler */
	Sock4 = 8,				/*!< TCP Client handler */
	Sock5 = 9,				/*!< TCP Client handler */
	Sock6 = 10,				/*!< TCP Client handler */
	Sock7 = 11,				/*!< TCP Client handler */
	Sock8 = 12,				/*!< TCP Client handler */
	Sock9 = 13,				/*!< TCP Client handler */
	Sock10 = 14,			/*!< TCP Client handler */
}SocketID_t;

/**
  * @brief	Enumerador dos ID's dos fd's select
  */
typedef enum
{
	Select_usart0 = 0,			/*!< USART 0 */
	Select_TCPServerSocket = 1,	/*!< TCP Server socket */
	Select_UDPServerSocket = 2,	/*!< UDP Server socket */
	Select_TCPClientSocket = 3,	/*!< TCP Client socket */
	Select_UDPClientSocket = 4,	/*!< UDP Client socket */
	Select_Sock0 = 5,			/*!< TCP Client handler */
	Select_Sock1 = 6,			/*!< TCP Client handler */
	Select_Sock2 = 7,			/*!< TCP Client handler */
	Select_Sock3 = 8,			/*!< TCP Client handler */
	Select_Sock4 = 9,			/*!< TCP Client handler */
	Select_Sock5 = 10,			/*!< TCP Client handler */
	Select_Sock6 = 11,			/*!< TCP Client handler */
	Select_Sock7 = 12,			/*!< TCP Client handler */
	Select_Sock8 = 13,			/*!< TCP Client handler */
	Select_Sock9 = 14,			/*!< TCP Client handler */
	Select_Sock10 = 15,			/*!< TCP Client handler */
}SelectID_t;

/**
  * @brief	Estrutura de dados para select
  */
typedef struct
{
	fd_set readfds;
	int max_fd;
}Select_t;

/**
  * @brief	Estrutura de dados para socket
  */
typedef struct
{
	char buf_rx[RX_BUF_LEN];
}SocketData_t;

/**
  * @brief	Enumerador de resultados
  */
typedef enum
{
	Result_NoCloud = -21,				/*!< Erro, sem internet */
	Result_NoConnection = -20,			/*!< Erro, sem conexão de rede */
	Result_IsBusy = -19,				/*!< Erro, módulo ocupado */
	Result_OnNetworkParameters = -18,	/*!< Erro nos Parâmetros de rede */
	Result_OnConnect = -17,				/*!< Erro ao conectar no socket */
	Result_IoctlError = -16,			/*!< Erro de acesso ao hardware */
	Result_OpenFile = -15,				/*!< Erro ao abrir o arquivo */
	Result_NoData = -14,				/*!< Erro, sem dados */
	Result_PortOpened = -13,			/*!< Erro, porta em uso */
	Result_AlreadyExists = -12,			/*!< Erro, já existe */
	Result_BadArgument = -11,			/*!< Erro, argumento inválido */
	Result_Desconnected = -10,			/*!< Erro, socket desconectado */
	Result_SocketClosed = -9,			/*!< Erro, socket fechado */
	Result_OnWrite = -8,				/*!< Error on write socket */
	Result_OnRead = -7,					/*!< Error on read socket */
	Result_OnAccept = -6,				/*!< Error on Accept socket */
	Result_OnListen = -5,				/*!< Error on listen socket */
	Result_OnBinding = -4,				/*!< Error on binding socket */
	Result_OnSet = -3,					/*!< Error on set socket */
	Result_OnOpen = -2,					/*!< Error on open socket */
	Result_Error = -1,					/*!< General error */
	Result_Ok = 0						/*!< General Ok */
}Result_t;

/**
  * @brief	Enumerador de socket status
  */
typedef enum
{
	Status_SocketClosed = -2,	/*!< Socket fechado */
	Status_SocketListen = -1,	/*!< Socket escutando */
	Status_SocketConnected = 0	/*!< Socket conectado */
}SocketStatus_t;

/**
  * @brief	Enumerador de connection status
  */
typedef enum
{
	Status_ConnectionDisconnected = -2,	/*!< Wi-Fi desconectado */
	Status_ConnectionConnecting = -1,	/*!< Wi-Fi conectando */
	Status_ConnectionConnected = 0,		/*!< Wi-Fi conectado como STA */
	Status_SoftAP = 1					/*!< Wi-Fi conectado como AP */
}ConnectionStatus_t;

/**
  * @brief	Enumerador de data status
  */
typedef enum
{
	IsRead = 0,		/*!< Há dados recebidos */
	NoRead = -1,	/*!< Não há dados recebidos */
	IsWrite = 0,	/*!< Há dados para enviar */
	NoWrite = -1	/*!< Não há dados para enviar */
}DataStatus_t;

/**
  * @brief	Enumerador de tipos de socket
  */
typedef enum
{
	TCP_CLIENT = 0,	/*!< Socket TCP Client */
	TCP_SERVER = 1,	/*!< Socket TCP Server */
	UDP_CLIENT = 2,	/*!< Socket UDP Client */
	UDP_SERVER = 3	/*!< Socket UDP Server */
}SocketType_t;

/**
  * @brief	Enumerador de tipos de rede
  */
typedef enum
{
	DHCP_NETWORK = 0,	/*!< Rede em modo dhcp */
	STATIC_NETWOTK = 1	/*!< Rede em modo statico */
}NetworkType_t;

/**
  * @brief	Enumerador de tipo bollean
  */
typedef enum
{
	FALSE = 0,	/*!< Falso */
	TRUE = 1	/*!< Verdade */
}BooleanType_t;

/**
  * @brief	Enumerador da serial
  */
typedef enum
{
	SERIAL_CONTROL = 0,	/*!< Serial de controle */
	SERIAL_DATA = 1		/*!< Serial de dados */
}SerialType_t;

/**
  * @brief	Enumerador de estados da FIFO
  */
typedef enum
{
	FIFO_ISEMPTY = 0,	/*!< FIFO vazia */
	FIFO_NOEMPTY = 1,	/*!< FIFO não está vazia */
	FIFO_ISFULL = 2,	/*!< FIFO cheia */
	FIFO_NOFULL = 3		/*!< FIFO não está cheia */
}FIFOStatus_t;

/**
  * @brief	Enumerador de tipos de variaveis da FIFO
  */
typedef enum
{
	FIFO_INT = 0,	/*!< FIFO int */
	FIFO_CHAR = 1,	/*!< FIFO char */
}FIFOType_t;

/**
  * @brief	Estrutura de dados para FIFO
  */
typedef struct
{
	void *buf;			/*!< Ponteiro p/ o buffer da FIFO */
    int head;			/*!< Cabeça da FIFO */
    int tail;			/*!< Cauda da FIFO */
    int size;			/*!< Tamanho da FIFO */
    FIFOType_t type;	/*!< Tipo de dados da FIFO */
}FIFO_t;

/**
  * @brief	Estrutura de socket
  */
typedef struct
{
	int  	 			ID;			/*!< ID interno do socket */
	int 				serfd;		/*!< Server File descriptor */
	int					clifd;		/*!< Client File descriptor */
	struct sockaddr_in 	seraddr;	/*!< Server Address */
	struct sockaddr_in 	cliaddr;	/*!< Client Address */
	int					porta;		/*!< Porta do socket */
	FIFO_t				fifo_rx;	/*!< Estrutura FIFO dados recebidos Rx */
	SocketData_t 		Data;		/*!< Data structure */
	DataStatus_t		isrx;		/*!< Se há dados recebidos */
	DataStatus_t		istx;		/*!< Se há dados a serem enviados */
	int					nb_rec;		/*!< Número parcial de bytes recebidos */
	int					nb_env;		/*!< Número parcial de bytes a serem enviados */
	int 				istimeout;	/*!< Contador de timeout */
	SocketStatus_t		status;		/*!< Status do socket */
	SocketType_t		type;		/*!< Tipo de socket TCP ou UDP */
}Socket_t;

/**
  * @}
  */

/* Exported functions --------------------------------------------------------*/

/* Funções principais */
void WF_GetRadioMAC(void);
void WF_GetIP(void);
void WF_GetRouterIP(void);
void WF_ConnectSofAP(char *ssid, char *key, char *sectype);
void WF_ConnectInfraKey(char *ssid, char *key, char *sectype);
void WF_ConnectionState(void);
void WF_Disconnect(void);
void WF_Scan(int rssi);
void WF_IsScanDone(void);
void WF_ScanResult(void);
void WF_PingIP(char *ip);
void WF_IsPingOK(void);
void SCK_IsRxDataReady(SocketID_t id);
void SCK_IsRxDataReady2(void);
void SCK_RxData(SocketID_t id);
void SCK_IsTxDataReady(SocketID_t id);
void SCK_TxData(SocketID_t id, int size);
void SCK_GetStatusSocket(SocketID_t id);
void SCK_Close(SocketID_t id);
void TCP_ConnClient(SocketID_t id, char *ip, int porta);
void TCP_OpenServer(int porta);
void UDP_OpenClient(SocketID_t id, char *ip, int porta);
void UDP_OpenServer(SocketID_t id, int porta);
void CFG_SetNetworkParameters(NetworkType_t type, char *ip, char *netmask, char *gateway);
void CFG_GetNetworkParameters(void);
void CFG_SetTimeOutSocket(int timeout);
void CFG_GetTimeOutSocket(void);
void CFG_SetTimeOutUSART(int timeout);
void CFG_GetTimeOutUSART(void);
void CFG_SetBaudRate(SerialType_t serial,int baudrate);
void CFG_GetBaudRate(SerialType_t serial);
void SW_Reboot(void);
void SW_GetVersion(void);
void SW_ClearBusy(void);
void SW_Execute(char *cmd);
void SW_ConnStatusConf(BooleanType_t conf);
void SW_RingConf(BooleanType_t conf);

/* Funções auxiliares */

/* Common */
void          aux_mkdir();
TaskID_t      aux_gettaskid(char *name);
char         *aux_itoa(int num);
void          aux_removec(char *s, char c, int len);
int           strcntc(char *s, char c);
void          aux_FileWrLine(char *path, char *filename, char *msg, char *errormsg);
char         *aux_FileRdLine(char *path, char *filename, char *errormsg);
void          aux_ClearFlags();
void          aux_SetBusy(BooleanType_t opt);
BooleanType_t aux_GetBusy();
BooleanType_t aux_IsNumber(char *s);
void 		  aux_back_functions(int sig);

/* serial */
void aux_USART_open();
int  aux_USART0_puts(const char *format, ...);
void aux_USART0_putc(const char *s, int len);
int  aux_USART1_puts(const char *format, ...);
void aux_USART1_putc(const char *s, int len);
int  aux_USART0_gets(char *s);
int  aux_USART1_gets(char *s, int len);

/* WF */
Result_t 		   aux_WF_PingIP(char *ip);
Result_t		   aux_WF_GetRouterIP(void);
char 			  *aux_WF_GetCharRouterIP(void);
Result_t 		   aux_WF_GetIP(void);
char 			  *aux_WF_GetCharIP(void);
ConnectionStatus_t aux_GetConnectionState(void);
void 			   aux_SetConnectionState(ConnectionStatus_t ConnectionStatus);

/* Socket */
void 	 aux_ClearSocket(SocketID_t id);
Result_t aux_CloseSocket(SocketID_t id);
void     aux_SendSignal(const char *format, ...);
void TCP_OpenServer_accept(SocketID_t id);
void TCP_OpenServer_recv(SocketID_t id);
void UDP_OpenServer_recv(SocketID_t id);
void TCP_ConnClient_recv(SocketID_t id);
void UDP_OpenClient_recv(SocketID_t id);
BooleanType_t SCK_CheckID(char *id);

/* Config */
void     aux_CFG_SetTimeOutSocket(int timeout);
void     aux_CFG_SetTimeOutUSART(int timeout);
int      aux_CFG_GetTimeOutSocket(void);
int      aux_CFG_GetTimeOutUSART(void);
Result_t aux_CFG_SetBaudRate(SerialType_t serial,int baudrate);
int      aux_CFG_GetBaudRate(SerialType_t serial);

/* FIFO */
void fifo_init(FIFO_t *f, void *buf, int size, FIFOType_t type);
FIFOStatus_t fifo_isempty(FIFO_t *f);
int fifo_read(FIFO_t *f, void *buf, int n);
int fifo_write(FIFO_t *f, const void *buf, int n);

/* Select */
void Select_Clear(void);
void Select_Set(void);
int Select_IsSet(SelectID_t SelectID);
void Select_Maxfd(void);
void Select_Exec(void);

/* Debug */
#ifdef DEBUG
void debug_init();
void debug_append(const char *format, ...);
#endif

#endif /* DEFINES_H_ */

/**
  * @}
  */




